package conf

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"sync"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB
var config *Config

func GetConf() *Config {
	return config
}
func NewDefaultConfig() *Config {
	return &Config{
		NewDefaultApp(),
		NewDefaultLog(),
		NewDefaultMysql(),
	}
}

type Config struct {
	App   *App   `toml:"app"`
	Log   *Log   `toml:"log"`
	MySQL *Mysql `toml:"mysql"`
}

/* type Config struct {
	*App   `toml:"app"`
	*Log   `toml:"log"`
	*Mysql `toml:"mysql"`
} */
func NewDefaultApp() *App {

	return &App{
		Name: "demo",
		Host: "127.0.0.1",
		Port: "8080",
	}
}

type App struct {
	Name string `toml:"name" env:"APP_NAME"`
	Host string `toml:"host" env:"APP_HOST"`
	Port string `toml:"port" env:"APP_PORT"`
}

func NewDefaultMysql() *Mysql {
	return &Mysql{
		Host:        "127.0.0.1",
		Port:        "3306",
		UserName:    "test",
		Password:    "test",
		Database:    "demo",
		MaxOpenConn: 10,
		MaxIdleConn: 5,
		MaxLifeTime: 60 * 60,
		MaxIdleTime: 60 * 60,
	}
}

type Mysql struct {
	Host        string `toml:"host" env:"MYSQL_HOST"`
	Port        string `toml:"port" env:"MYSQL_PORT"`
	UserName    string `toml:"username" env:"MYSQL_USERNAME"`
	Password    string `toml:"password" env:"MYSQL_PASSWORD"`
	Database    string `toml:"database" env:"MYSQL_DATABASE"`
	MaxOpenConn int    `toml:"max_open_conn" env:"MYSQL_MAX_OPEN_CONN"`
	MaxIdleConn int    `toml:"max_idle_conn" env:"MYSQL_MAX_IDLE_CONN"`
	MaxLifeTime int    `toml:"max_life_time" env:"MYSQL_MAX_LIFE_TIME"`
	MaxIdleTime int    `toml:"max_idle_time" env:"MYSQL_MAX_idle_TIME"`
	lock        sync.RWMutex
}

func (m *Mysql) GetDB() *sql.DB {

	m.lock.Lock()
	defer m.lock.Unlock()
	if db == nil {
		con, err := m.getDBcon()
		if err != nil {
			db = con
		}
	}
	return db
}
func (m *Mysql) getDBcon() (*sql.DB, error) {

	//设置dsn
	//连接数据库
	var err error
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&multiStatements=true", m.UserName, m.Password, m.Host, m.Port, m.Database)
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("connect to mysql<%s> error, %s", dsn, err.Error())
		// return nil, log.Fatalf("connect to mysql<%s> error, %s", dsn, err.Error())
	}
	db.SetMaxOpenConns(m.MaxOpenConn)
	db.SetMaxIdleConns(m.MaxIdleConn)
	db.SetConnMaxLifetime(time.Second * time.Duration(m.MaxLifeTime))
	db.SetConnMaxIdleTime(time.Second * time.Duration(m.MaxIdleTime))
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := db.PingContext(ctx); err != nil {
		return nil, fmt.Errorf("ping mysql<%s> error, %s", dsn, err.Error())
	}
	return db, nil

}

func NewDefaultLog() *Log {
	return &Log{
		Level:   "info",
		Format:  TextFormat,
		To:      ToStdout,
		PathDir: "dir",
	}
}

type Log struct {
	Level string `toml:"level" env:"LOG_LEVEL"`

	Format  LogFormat `toml:"format" env:"LOG_FORMAT"`
	To      LogTo     `toml:"to" env:"LOG_TO"`
	PathDir string    `toml:"path_dir" env:"LOG_PATH_DIR"`
}
